//// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
//package com.linqingying.cangnova.ide.impl.util.newProjectWizard;
//
//import com.intellij.facet.impl.ui.libraries.LibraryCompositionSettings;
//import com.intellij.facet.impl.ui.libraries.LibraryOptionsPanel;
//import com.intellij.facet.ui.FacetBasedFrameworkSupportProvider;
//import com.intellij.framework.FrameworkGroup;
//import com.intellij.framework.FrameworkVersion;
//import com.intellij.framework.addSupport.FrameworkSupportInModuleConfigurable;
//import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider;
//import com.intellij.framework.addSupport.FrameworkVersionListener;
//import com.intellij.ide.JavaUiBundle;
//import com.intellij.ide.util.frameworkSupport.FrameworkSupportConfigurable;
//import com.intellij.ide.util.frameworkSupport.FrameworkSupportProvider;
//import com.intellij.ide.util.frameworkSupport.FrameworkSupportUtil;
//import com.intellij.ide.util.newProjectWizard.impl.FrameworkSupportCommunicator;
//import com.intellij.ide.util.newProjectWizard.impl.FrameworkSupportModelBase;
//import com.intellij.openapi.Disposable;
//import com.intellij.openapi.diagnostic.Logger;
//import com.intellij.openapi.module.Module;
//import com.intellij.openapi.roots.IdeaModifiableModelsProvider;
//import com.intellij.openapi.roots.ModifiableRootModel;
//import com.intellij.openapi.roots.libraries.Library;
//import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer;
//import com.intellij.openapi.ui.Messages;
//import com.intellij.openapi.ui.Splitter;
//import com.intellij.openapi.util.Comparing;
//import com.intellij.openapi.util.text.StringUtil;
//import com.intellij.ui.CheckedTreeNode;
//import com.intellij.ui.ScrollPaneFactory;
//import com.intellij.util.containers.ContainerUtil;
//import com.intellij.util.ui.JBInsets;
//import com.intellij.util.ui.JBUI;
//import com.intellij.util.ui.UIUtil;
//import org.jetbrains.annotations.NonNls;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//import javax.swing.*;
//import javax.swing.event.TreeSelectionEvent;
//import javax.swing.event.TreeSelectionListener;
//import javax.swing.tree.DefaultTreeModel;
//import java.awt.*;
//import java.util.List;
//import java.util.*;
//
//public class AddSupportForFrameworksPanel implements Disposable {
//  private static final Logger LOG = Logger.getInstance(AddSupportForFrameworksPanel.class);
//  @NonNls private static final String EMPTY_CARD = "empty";
//  private JPanel myMainPanel;
//  private JPanel myFrameworksPanel;
//  private JLabel myLabel;
//
//  private List<? extends FrameworkSupportInModuleProvider> myProviders;
//  private List<FrameworkSupportNodeBase<?>> myRoots;
//
//  private final LibrariesContainer myLibrariesContainer;
//  private final FrameworkSupportModelBase myModel;
//  private final JPanel myOptionsPanel;
//  private final FrameworksTree myFrameworksTree;
//  private final Map<FrameworkSupportNode, FrameworkSupportOptionsComponent> myInitializedOptionsComponents = new HashMap<>();
//  private final Map<FrameworkGroup<?>, JPanel> myInitializedGroupPanels = new HashMap<>();
//  private FrameworkSupportNodeBase<?> myLastSelectedNode;
//
//  private Collection<FrameworkSupportNodeBase<?>> myAssociatedFrameworks;
//  @Nullable
//  private final JPanel myAssociatedFrameworksPanel;
//
//  public AddSupportForFrameworksPanel(final List<FrameworkSupportInModuleProvider> providers,
//                                      final FrameworkSupportModelBase model, boolean vertical, @Nullable JPanel associatedFrameworksPanel) {
//    myModel = model;
//    myAssociatedFrameworksPanel = associatedFrameworksPanel;
//    myLibrariesContainer = model.getLibrariesContainer();
//
//    myLabel.setVisible(!vertical);
//    Splitter splitter = vertical ? new Splitter(true, 0.6f, 0.2f, 0.8f) : new Splitter(false, 0.3f, 0.3f, 0.7f);
//    splitter.setHonorComponentsMinimumSize(false);
//    myFrameworksTree = new FrameworksTree(model) {
//      @Override
//      protected void onNodeStateChanged(CheckedTreeNode node) {
//        if (!(node instanceof FrameworkSupportNode frameworkSupportNode)) return;
//
//        if (frameworkSupportNode == getSelectedNode()) {
//          updateOptionsPanel();
//        }
//        final FrameworkSupportInModuleConfigurable configurable = frameworkSupportNode.getConfigurable();
//        configurable.onFrameworkSelectionChanged(node.isChecked());
//        myModel.onFrameworkSelectionChanged(frameworkSupportNode);
//        onFrameworkStateChanged();
//      }
//    };
//    model.addFrameworkVersionListener(new FrameworkVersionListener() {
//      @Override
//      public void versionChanged(FrameworkVersion version) {
//        ((DefaultTreeModel)myFrameworksTree.getModel()).nodeChanged(getSelectedNode());
//      }
//    }, this);
//
//    myFrameworksTree.addTreeSelectionListener(new TreeSelectionListener() {
//      @Override
//      public void valueChanged(TreeSelectionEvent e) {
//        onSelectionChanged();
//      }
//    });
//
//    JPanel treePanel = new JPanel(new BorderLayout());
//    treePanel.add(ScrollPaneFactory.createScrollPane(myFrameworksTree), BorderLayout.CENTER);
//    treePanel.setMinimumSize(JBUI.size(200, 300));
//
//    splitter.setFirstComponent(treePanel);
//    myOptionsPanel = new JPanel(new CardLayout());
//    JPanel emptyCard = new JPanel();
//    emptyCard.setPreferredSize(JBUI.size(400, 100));
//    myOptionsPanel.add(EMPTY_CARD, emptyCard);
//
//    splitter.setSecondComponent(myOptionsPanel);
//    myFrameworksPanel.add(splitter, BorderLayout.CENTER);
//
//    setProviders(providers);
//  }
//
//  public void setProviders(List<? extends FrameworkSupportInModuleProvider> providers) {
//    setProviders(providers, Collections.emptySet(), Collections.emptySet());
//  }
//
//  public void setProviders(List<? extends FrameworkSupportInModuleProvider> providers, Set<String> associated, Set<String> preselected) {
//    myProviders = providers;
//
//    myAssociatedFrameworks = createNodes(myProviders, associated, preselected);
//    setAssociatedFrameworks();
//
//    myFrameworksTree.setRoots(myRoots);
//    myFrameworksTree.setSelectionRow(0);
//
//    for (FrameworkSupportNodeBase<?> node : myRoots) {
//      if (preselected.contains(node.getId())) {
//        // we need to trigger `FrameworksTree::onNodeStateChanged`
//        // in order to preconfigure `FrameworkSupportNode`s
//        myFrameworksTree.setNodeState(node, true);
//      }
//    }
//  }
//
//  public void setAssociatedFrameworks() {
//
//    if (myAssociatedFrameworksPanel == null) return;
//    for (FrameworkSupportNodeBase<?> nodeBase : myAssociatedFrameworks) {
//      if (nodeBase instanceof FrameworkSupportNode) {
//        ((FrameworkSupportNode)nodeBase).getConfigurable().onFrameworkSelectionChanged(true);
//        FrameworkSupportOptionsComponent component = initializeOptionsPanel((FrameworkSupportNode)nodeBase, false);
//        addAssociatedFrameworkComponent(component.getMainPanel(), myAssociatedFrameworksPanel);
//      }
//      else {
//        JPanel panel = initializeGroupPanel((FrameworkGroup<?>)nodeBase.getUserObject(), false);
//        addAssociatedFrameworkComponent(panel, myAssociatedFrameworksPanel);
//      }
//    }
//  }
//
//  private static void addAssociatedFrameworkComponent(JPanel component, JPanel panel) {
//    panel.add(component, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0, GridBagConstraints.NORTHWEST,
//                                                GridBagConstraints.HORIZONTAL, JBInsets.emptyInsets(), 0, 0));
//  }
//
//  protected void onFrameworkStateChanged() {}
//
//  private void onSelectionChanged() {
//    if (!myFrameworksTree.isProcessingMouseEventOnCheckbox()) {
//      updateOptionsPanel();
//    }
//
//    final FrameworkSupportNodeBase<?> selectedNode = getSelectedNode();
//    if (!Comparing.equal(selectedNode, myLastSelectedNode)) {
//      applyLibraryOptionsForSelected();
//
//      myLastSelectedNode = selectedNode;
//    }
//  }
//
//  @Override
//  public void dispose() {
//  }
//
//  private void applyLibraryOptionsForSelected() {
//    if (myLastSelectedNode instanceof FrameworkSupportNode) {
//      final FrameworkSupportOptionsComponent optionsComponent = myInitializedOptionsComponents.get((FrameworkSupportNode)myLastSelectedNode);
//      if (optionsComponent != null) {
//        final LibraryOptionsPanel optionsPanel = optionsComponent.getLibraryOptionsPanel();
//        if (optionsPanel != null) {
//          optionsPanel.apply();
//        }
//      }
//    }
//  }
//
//  private void updateOptionsPanel() {
//    final FrameworkSupportNodeBase<?> node = getSelectedNode();
//    if (node instanceof FrameworkSupportNode frameworkSupportNode) {
//      initializeOptionsPanel(frameworkSupportNode, true);
//      showCard(frameworkSupportNode.getId());
//      UIUtil.setEnabled(myOptionsPanel, frameworkSupportNode.isChecked(), true);
//      frameworkSupportNode.getConfigurable().onFrameworkSelectionChanged(node.isChecked());
//    }
//    else if (node instanceof FrameworkGroupNode) {
//      FrameworkGroup<?> group = ((FrameworkGroupNode)node).getUserObject();
//      initializeGroupPanel(group, true);
//      showCard(group.getId());
//      UIUtil.setEnabled(myOptionsPanel, true, true);
//    }
//    else {
//      showCard(EMPTY_CARD);
//    }
//  }
//
//  private JPanel initializeGroupPanel(FrameworkGroup<?> group, boolean addToOptions) {
//    JPanel panel = myInitializedGroupPanels.get(group);
//    if (panel == null) {
//      FrameworkVersionComponent component = new FrameworkVersionComponent(myModel, group.getId(), group.getGroupVersions(),
//                                                                          JavaUiBundle.message("add.framework.support.label.version", group.getPresentableName()));
//      panel = component.getMainPanel();
//      myInitializedGroupPanels.put(group, panel);
//      if (addToOptions) {
//        myOptionsPanel.add(group.getId(), wrapInScrollPane(panel));
//      }
//    }
//    return panel;
//  }
//
//  @Nullable
//  public FrameworkSupportNodeBase<?> getSelectedNode() {
//    final FrameworkSupportNodeBase<?>[] nodes = myFrameworksTree.getSelectedNodes(FrameworkSupportNodeBase.class, null);
//    return nodes.length == 1 ? nodes[0] : null;
//  }
//
//  private FrameworkSupportOptionsComponent initializeOptionsPanel(final FrameworkSupportNode node, boolean addToOptions) {
//    FrameworkSupportOptionsComponent component = myInitializedOptionsComponents.get(node);
//    if (component == null) {
//      final FrameworkSupportNodeBase<?> parentNode = node.getParentNode();
//      if (parentNode instanceof FrameworkSupportNode) {
//        initializeOptionsPanel((FrameworkSupportNode)parentNode, addToOptions);
//      }
//      else if (parentNode instanceof FrameworkGroupNode) {
//        initializeGroupPanel(((FrameworkGroupNode)parentNode).getUserObject(), addToOptions);
//      }
//
//      component = new FrameworkSupportOptionsComponent(myModel, myLibrariesContainer, this,
//                                                       node.getUserObject(), node.getConfigurable());
//      if (addToOptions) {
//        myOptionsPanel.add(node.getId(), wrapInScrollPane(component.getMainPanel()));
//      }
//      myInitializedOptionsComponents.put(node, component);
//    }
//    return component;
//  }
//
//  private static JScrollPane wrapInScrollPane(JPanel panel) {
//    JPanel wrapper = new JPanel(new BorderLayout());
//    wrapper.add(panel);
//    wrapper.setBorder(JBUI.Borders.empty(5));
//    return ScrollPaneFactory.createScrollPane(wrapper, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
//                                              ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//  }
//
//  private void showCard(String cardName) {
//    ((CardLayout)myOptionsPanel.getLayout()).show(myOptionsPanel, cardName);
//  }
//
//  private List<LibraryCompositionSettings> getLibrariesCompositionSettingsList() {
//    List<LibraryCompositionSettings> list = new ArrayList<>();
//    List<FrameworkSupportNode> selected = getSelectedNodes();
//    for (FrameworkSupportNode node : selected) {
//      ContainerUtil.addIfNotNull(list, getLibraryCompositionSettings(node));
//    }
//    return list;
//  }
//
//  @Nullable
//  private LibraryCompositionSettings getLibraryCompositionSettings(FrameworkSupportNode node) {
//    final FrameworkSupportOptionsComponent optionsComponent = myInitializedOptionsComponents.get(node);
//    return optionsComponent != null ? optionsComponent.getLibraryCompositionSettings() : null;
//  }
//
//  private Collection<FrameworkSupportNodeBase<?>> createNodes(List<? extends FrameworkSupportInModuleProvider> providers,
//                                                           Set<String> associated,
//                                                           final Collection<String> preselected) {
//    Map<String, FrameworkSupportNode> nodes = new HashMap<>();
//    Map<FrameworkGroup<?>, FrameworkGroupNode> groups = new HashMap<>();
//    List<FrameworkSupportNodeBase<?>> roots = new ArrayList<>();
//    Map<String, FrameworkSupportNodeBase<?>> associatedNodes = new LinkedHashMap<>();
//    for (FrameworkSupportInModuleProvider provider : providers) {
//      createNode(provider, nodes, groups, roots, providers, associated, associatedNodes);
//    }
//
//    FrameworkSupportNodeBase.sortByName(roots,
//                                        (o1, o2) -> Boolean.compare(preselected.contains(o2.getId()), preselected.contains(o1.getId())));
//    myRoots = roots;
//    return associatedNodes.values();
//  }
//
//  @Nullable
//  private FrameworkSupportNode createNode(final FrameworkSupportInModuleProvider provider,
//                                          final Map<String, FrameworkSupportNode> nodes,
//                                          final Map<FrameworkGroup<?>, FrameworkGroupNode> groupNodes,
//                                          List<? super FrameworkSupportNodeBase<?>> roots,
//                                          List<? extends FrameworkSupportInModuleProvider> providers,
//                                          Set<String> associated,
//                                          Map<String, FrameworkSupportNodeBase<?>> associatedNodes) {
//    String id = provider.getFrameworkType().getId();
//    FrameworkSupportNode node = nodes.get(id);
//    if (node != null || associatedNodes.containsKey(id)) {
//      return node;
//    }
//    String underlyingTypeId = provider.getFrameworkType().getUnderlyingFrameworkTypeId();
//    FrameworkSupportNodeBase<?> parentNode = null;
//    final FrameworkGroup<?> group = provider.getFrameworkType().getParentGroup();
//    if (underlyingTypeId != null) {
//      FrameworkSupportInModuleProvider parentProvider = FrameworkSupportUtil.findProvider(underlyingTypeId, providers);
//      if (parentProvider == null) {
//        LOG.info("Cannot find id = " + underlyingTypeId);
//        return null;
//      }
//      parentNode = createNode(parentProvider, nodes, groupNodes, roots, providers, associated, associatedNodes);
//    }
//    else if (group != null) {
//      parentNode = groupNodes.get(group);
//      if (parentNode == null) {
//        FrameworkGroupNode groupNode = new FrameworkGroupNode(group, null);
//        if (associated.contains(groupNode.getId())) {
//          associatedNodes.put(groupNode.getId(), groupNode);
//        }
//        else {
//          groupNodes.put(group, groupNode);
//          parentNode = groupNode;
//          roots.add(groupNode);
//        }
//      }
//    }
//    node = new FrameworkSupportNode(provider, parentNode, myModel, this);
//    if (associated.contains(id)) {
//      associatedNodes.put(id, node);
//    }
//    else {
//      nodes.put(id, node);
//      if (parentNode == null) {
//        roots.add(node);
//      }
//    }
//    return node;
//  }
//
//  public JComponent getMainPanel() {
//    return myMainPanel;
//  }
//
//  public FrameworksTree getFrameworksTree() {
//    return myFrameworksTree;
//  }
//
//  public boolean hasSelectedFrameworks() {
//    return !getSelectedNodes().isEmpty();
//  }
//
//  public List<FrameworkSupportNode> getSelectedNodes() {
//    List<FrameworkSupportNode> list = new ArrayList<>();
//    if (myRoots != null) {
//      addChildFrameworks(myRoots, list);
//    }
//    list.addAll(ContainerUtil.findAll(myAssociatedFrameworks, FrameworkSupportNode.class));
//    return list;
//  }
//
//  private static void addChildFrameworks(final List<? extends FrameworkSupportNodeBase<?>> list, final List<? super FrameworkSupportNode> result) {
//    for (FrameworkSupportNodeBase<?> node : list) {
//      if (node.isChecked() || node instanceof FrameworkGroupNode) {
//        if (node instanceof FrameworkSupportNode) {
//          result.add((FrameworkSupportNode)node);
//        }
//        addChildFrameworks(node.getChildren(), result);
//      }
//    }
//  }
//
//  public boolean downloadLibraries(@NotNull final JComponent parentComponent) {
//    applyLibraryOptionsForSelected();
//    for (LibraryCompositionSettings compositionSettings : getLibrariesCompositionSettingsList()) {
//      if (!compositionSettings.downloadFiles(parentComponent)) {
//        int answer = Messages.showYesNoDialog(parentComponent,
//                                              JavaUiBundle.message("warning.message.some.required.libraries.wasn.t.downloaded"),
//                                              JavaUiBundle.message("dialog.title.libraries.are.required"), Messages.getWarningIcon());
//        return answer == Messages.YES;
//      }
//    }
//
//    return true;
//  }
//
//  public boolean validate() {
//    applyLibraryOptionsForSelected();
//    List<String> frameworksWithoutRequiredLibraries = new ArrayList<>();
//    for (FrameworkSupportNode node : getSelectedNodes()) {
//      if (node.getConfigurable().isOnlyLibraryAdded()) {
//        LibraryCompositionSettings librarySettings = getLibraryCompositionSettings(node);
//        if (librarySettings != null && !librarySettings.isLibraryConfigured()) {
//          frameworksWithoutRequiredLibraries.add(node.getTitle());
//        }
//      }
//    }
//
//    if (!frameworksWithoutRequiredLibraries.isEmpty()) {
//      String frameworksText = StringUtil.join(frameworksWithoutRequiredLibraries, ", ");
//      Messages.showErrorDialog(myMainPanel, JavaUiBundle.message("error.message.required.library.is.not.configured", frameworksText, frameworksWithoutRequiredLibraries.size()),
//                               JavaUiBundle.message("error.title.required.library.is.not.configured"));
//      return false;
//    }
//    return true;
//  }
//
//  public void addSupport(final @NotNull Module module, final @NotNull ModifiableRootModel rootModel) {
//    List<Library> addedLibraries = new ArrayList<>();
//    List<FrameworkSupportNode> selectedFrameworks = getSelectedNodes();
//    sortFrameworks(selectedFrameworks);
//    List<FrameworkSupportConfigurable> selectedConfigurables = new ArrayList<>();
//    final IdeaModifiableModelsProvider modifiableModelsProvider = new IdeaModifiableModelsProvider();
//    for (FrameworkSupportNode node : selectedFrameworks) {
//      FrameworkSupportInModuleConfigurable configurable = node.getConfigurable();
//      if (configurable instanceof OldFrameworkSupportProviderWrapper.FrameworkSupportConfigurableWrapper) {
//        selectedConfigurables.add(((OldFrameworkSupportProviderWrapper.FrameworkSupportConfigurableWrapper)configurable).getConfigurable());
//      }
//      final LibraryCompositionSettings settings = getLibraryCompositionSettings(node);
//      Library library = settings != null ? settings.addLibraries(rootModel, addedLibraries, myLibrariesContainer) : null;
//      if (configurable instanceof OldFrameworkSupportProviderWrapper.FrameworkSupportConfigurableWrapper) {
//        ((OldFrameworkSupportProviderWrapper.FrameworkSupportConfigurableWrapper)configurable).getConfigurable().addSupport(module, rootModel,
//                                                                                                                         library);
//      }
//      else {
//        configurable.addSupport(module, rootModel, modifiableModelsProvider);
//      }
//    }
//    for (FrameworkSupportNode node : selectedFrameworks) {
//      FrameworkSupportInModuleProvider provider = node.getUserObject();
//      if (provider instanceof OldFrameworkSupportProviderWrapper) {
//        final FrameworkSupportProvider oldProvider = ((OldFrameworkSupportProviderWrapper)provider).getProvider();
//        if (oldProvider instanceof FacetBasedFrameworkSupportProvider && !addedLibraries.isEmpty()) {
//          ((FacetBasedFrameworkSupportProvider<?>)oldProvider).processAddedLibraries(module, addedLibraries);
//        }
//      }
//    }
//    for (FrameworkSupportCommunicator communicator : FrameworkSupportCommunicator.EP_NAME.getExtensions()) {
//      communicator.onFrameworkSupportAdded(module, rootModel, selectedConfigurables, myModel);
//    }
//  }
//
//  private void sortFrameworks(final List<? extends FrameworkSupportNode> nodes) {
//    final Comparator<FrameworkSupportInModuleProvider> comparator = FrameworkSupportUtil.getFrameworkSupportProvidersComparator(myProviders);
//    nodes.sort((o1, o2) -> comparator.compare(o1.getUserObject(), o2.getUserObject()));
//  }
//
//}
